package com.xc.stock.domain.basic.convert;

import java.beans.PropertyDescriptor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.beans.BeanUtils;

import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.xc.stock.utils.Beans;

public class SimpleEntityPOConvert<E, P> implements IEntityPOConvert<E, P> {
	private Class<E> entityClass = null;
	private Class<P> poClass = null;

	@SuppressWarnings("unchecked")
	Class<E> entityClass() {
		if (entityClass != null) {
			return entityClass;
		}

//		TypeVariable<?>[] variables = this.getClass().getTypeParameters();
//		if(variables != null) {
//			entityClass = (Class<E>) (Type) variables[0];
//		} else {
			Type superclass = getClass().getGenericSuperclass();
			if (superclass instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType) superclass;
				Type[] types = parameterizedType.getActualTypeArguments();
				entityClass = (Class<E>) types[0];
			}
//		}

		return entityClass;
	}

	@SuppressWarnings("unchecked")
	Class<P> poClass() {
		if (poClass != null) {
			return poClass;
		}
		
//		Type[] variables = this.getClass().getTypeParameters();
//		if(variables != null) {
//			poClass = (Class<P>) variables[1];
//		} else {
			Type superclass = getClass().getGenericSuperclass();
			if (superclass instanceof ParameterizedType) {
				ParameterizedType parameterizedType = (ParameterizedType) superclass;
				Type[] types = parameterizedType.getActualTypeArguments();
				poClass = (Class<P>) types[1];
			}
//		}

		return poClass;
	}
	
	@Override
	public String[] ignoreProperties() {
		Class<P> poClass = poClass();
		Class<E> entityClass = entityClass();
		
		//取 entity 多余的部分
		PropertyDescriptor[] entityPropertyDescriptors = BeanUtils.getPropertyDescriptors(entityClass);
		PropertyDescriptor[] poPropertyDescriptors = BeanUtils.getPropertyDescriptors(poClass);
		
		List<String> entityList = Stream.of(entityPropertyDescriptors).map(PropertyDescriptor::getName).collect(Collectors.toList());
		List<String> poList = Stream.of(poPropertyDescriptors).map(PropertyDescriptor::getName).collect(Collectors.toList());
		Collection<String> diff = Collections2.filter(entityList, Predicates.not(Predicates.in(poList)));
//		List<String> diff = CollectionUtils.compareLatterFindDiff(poList, entityList);
		
		String[] diffArr = new String[ diff.size() ];
		return diff.toArray(diffArr);
	}

	@Override
	public P toPo(E e) {
		if(e == null) return null;
		
		P p = null;
		try {
			p = poClass().newInstance();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		}
		Beans.copyProperties(e, p);
		return p;
//		return Beans.mapper(e, poClass());
	}

	@Override
	public E toEntity(P p) {
		if(p == null) return null;
		
		E e = null;
		try {
			e = entityClass().newInstance();
		} catch (InstantiationException e1) {
			e1.printStackTrace();
		} catch (IllegalAccessException e1) {
			e1.printStackTrace();
		}
		Beans.copyProperties(p, e);
		
//		return Beans.mapper(p, entityClass());
		return e;
	}

}
